<?php
/**
 * appRain CMF
 *
 * LICENSE
 *
 * This source file is subject to the MIT license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.opensource.org/licenses/mit-license.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@apprain.com so we can send you a copy immediately.
 *
 * @copyright  Copyright (c) 2010 appRain, Team. (http://www.apprain.com)
 * @license    http://www.opensource.org/licenses/mit-license.php MIT license
 *
 * HELP
 *
 * Official Website
 * http://www.apprain.com/
 *
 * Download Link
 * http://www.apprain.com/download
 *
 * Documents Link
 * http ://www.apprain.com/docs
 */

$appLoc = dirname(__FILE__) ."/apprain/base/config.php";

if (!file_exists($appLoc)){
    die( "appRain core file(s) missing... Get a new copy ");
    exit;
}

require_once $appLoc;

final class App
{
    const SUPPERADMINLOGINID = 0;
    const USERSTATUSRESETID = -1;
    static public  $__userStatusId 	= self::USERSTATUSRESETID;

    static public  $__appData = Array();
    static private $_appDef = NULL;
    static private $__appObj = Array();
    static private $__hash_table = Array(
        "Model"     =>"Model",
        "Module"    =>"appRain_Base_Modules_",
        "Helper"    =>"Development_Helper_",
        "Plugin"    =>"Development_Plugin_",
        "Installer" =>"Development_Models_Installer_",
        "Component" =>"Component_"
    );

    public static function getBaseDir()
    {
        return dirname(__FILE__);
    }

    public static function __pathToClass($path="",$isObject=true)
    {
        $p = str_replace(self::getBaseDir() . DS,"",$path);
        $p = str_replace(DS,CDS,$p);
        $cn = str_replace(SEXT,"",$p);
        return ($isObject) ? self::__obj($cn) : $cn;
    }

    public static function getBaseUrl()
    {
        return  
            substr(
                dirname($_SERVER["PHP_SELF"]),
                0,
                (
                    (
                        strrpos(
                            dirname(
                                $_SERVER["PHP_SELF"]
                            ),
                            "webroot"
                        )
                    )-1
                )
            );
    }

    public static function __def()
    {
        if(!isset(self::$_appDef) ){
            self::$_appDef = self::load('Module/Definition');
        }

        return self::$_appDef;
    }

    public static function __obj( $class_name )
    {
        if( !isset(self::$__appObj[strtolower($class_name)])){
             self::$__appObj[strtolower($class_name)] = new $class_name();
        }

        return self::$__appObj[strtolower($class_name)] ;
    }

    public static function get( $__key = null )
    {
        return isset(self::$__appData[$__key]) ? self::$__appData[$__key] : self::$__appData;
    }

    public static function setUserStatusId($ID)
    {
        switch(strtoupper($ID)){
            case 'RESET' :
                self::$__userStatusId = self::USERSTATUSRESETID;
                break;
            case 'SUPERADMIN' :
            case 'SUPPERADMIN': 
                self::$__userStatusId = self::SUPPERADMINLOGINID;
                break;
            default :
                self::$__userStatusId = $ID;
                break;
        }
    }

    public static function getUserStatusId($ID = NULL)
    {
        if(isset($ID)){
            return $ID;
        }
        else if(self::$__userStatusId != self::USERSTATUSRESETID ){
            return self::$__userStatusId;
        }
        else{
            return self::Module('Membermanager')->loggedInId();
        }
    }

    public static function AdminManager()
    {
        return self::Module("AdminManager")->AdminManager();
    }

    public static function memberManager()
    {
        return self::Module("memberManager")->memberManager();
    }

    public static function PageManager($id = NULL)
    {
        if(isset($id)){
            self::setUserStatusId($id);
        }
        return self::Module("PageManager")->PageManager();
    }

    public static function categorySet($type = NULL)
    {
        return self::Module("categorySet")->categorySet($type);
    }

    public static function informationSet($type = NULL)
    {
        return self::Module("InformationSet")->InformationSet($type);
    }

    public static function helper($name = NULL)
    {
        return isset($name) ? self::load("Helper/{$name}") : NULL;
    }

    public static function module($name = NULL)
    {
        return isset($name) ? self::load("Module/{$name}") : NULL;
    }

    public static function Session()
    {
        return App::Module('Session');
    }

    public static function Config()
    {
        return App::Helper('Config');
    }

    public static function model($name = 'Home')
    {
        return isset($name) ? self::load("Model/{$name}") : NULL;
    }

    public static function plugin($name = NULL)
    {
        return isset($name) ? self::load("Plugin/{$name}") : NULL;
    }

    public static function component($name = NULL)
    {
        return isset($name) ? self::load("Component/{$name}_" . appRain_Base_component::BOOT_FILE) : NULL;
    }

    public static function hook($name = NULL)
    {
        return self::module('Hook')->setName($name);
    }

    public static function load( $hash )
    {
        $tags = explode("/",$hash);

        if(!isset(self::$__hash_table[$tags[0]]) || count($tags) < 2){
            if( self::__def()->sysConfig('DEBUG_MODE') > 0){
                pre( ("Error : Invalide hash({$hash}) has tried to load. Uses app::load('Module/Session')  "));
            }
            return false;
        }

        switch( strtolower($tags[0]))
        {
            case "model" :
                return self::__obj(
                    (
                        strtolower(
                            $tags[1]).self::$__hash_table[$tags[0]]
                        )
                    );
                    break;
            default	:
                return self::__obj((self::$__hash_table[$tags[0]] . $tags[1] ));
        }

    }

    public static function call($__class, $__method, $__param = Array())
    {
        if(method_exists($__class,$__method)){
            call_user_func_array(array($__class, $__method ),$__param);
        }
    }

    public static function __transfer($suri = null)
    {
        if($suri === null){
            header(
                "location:" 
                . "http://" 
                . $_SERVER['HTTP_HOST'] 
                . substr($_SERVER["PHP_SELF"],0,(strpos($_SERVER["PHP_SELF"],"/webroot"))) 
                . app::__def()->sysConfig('URL_FOR_404_PAGE')
            );
        }
        else
        {
            header(
                "location:" 
                . "http://" 
                . $_SERVER['HTTP_HOST'] 
                . substr($_SERVER["PHP_SELF"],0,(strpos($_SERVER["PHP_SELF"],"/webroot"))) 
                . $suri
            );
        }
        exit;
    }

    public static function run()
    {
        $arrCaller = Array();
        $arrParams = Array();

        self::__def();
        App::__def()->getComponentList();
        $definition = self::__def()->getURIManagerDefinition();

        if(!empty($_GET)){
            $_GET['basicrout'] = isset($_GET['basicrout']) ? str_replace(self::$_appDef->sysConfig('URI_SEPARATOR_MASK'),DS,$_GET['basicrout']) : "";

            $arry2call = explode(DS,$_GET['basicrout']);

             # Page routing section
             if( !empty($definition['pagerouter'])){
                 foreach($definition['pagerouter'] as $key => $val ){
                    if( $arry2call[0] == $val["virtual"][0]){
                        if( self::$_appDef->sysConfig('ROUTING_MODE') == "COMPACT"){
                            unset($arry2call[0]);
                            $arry2call = array_merge($val["actual"],$arry2call);
                        }
                        else if( self::$_appDef->sysConfig('ROUTING_MODE') == "EXTENDED"){
                            $sliced	= array_slice($arry2call,0,count($val['virtual']));
                            $rnt	= array_diff($sliced,$val['virtual']);
                            if( empty($rnt )){$arry2call = $val['actual'] + $arry2call;}
                        }
                    }
                 }
             }

            # Format all $_GET parameters
            foreach(  $arry2call as $key => $val ){
                if( $key > 1 ){
                    $arrParams[] = $val;
                }
            }
        }

        # Just to be safe
        $arry2call[0] = (isset($arry2call[0])) ? $arry2call[0] : '';
        $arry2call[1] = (isset($arry2call[1])) ? $arry2call[1] : '';
       

        # Set Controller and Methods
        if( $arry2call[0] == ''){
            $arrCaller['controller'] = isset($definition['bootrouter']['controller'])
                ? $definition['bootrouter']['controller'] : 'home';

            $arrCaller['action'] = isset($definition['bootrouter']['action']) 
                ? $definition['bootrouter']['action'] : 'index';
        }
        else
        {

            $arrCaller['controller'] = $arry2call[0];
            $arrCaller['action'] = ($arry2call[1] != '') ? $arry2call[1] : 'index';
        }

        
        $page_router = $definition['pagerouter'];

        # Do some secutity process
        if( !empty($page_router)){
            foreach($page_router as $key => $val ){
                $virtual_controller	= isset($val['virtual'][0]) ? $val['virtual'][0] : '';
                $virtual_action		= isset($val['virtual'][1]) ? $val['virtual'][1] : 'index';

                if( $virtual_controller == $arrCaller['controller'] && $virtual_action == $arrCaller['action']){
                    $arrCaller['controller'] = $val['actual'][0];
                    $arrCaller['action']	 = $val['actual'][1];
                }
            }
        }

        # Normalize Controller Name and Method
        $arrCaller['controller'] = str_replace(self::$_appDef->sysConfig('URI_MASK'),'_',$arrCaller['controller']);
        $arrCaller['action'] = str_replace(self::$_appDef->sysConfig('URI_MASK'),'_',$arrCaller['action']);

        # Assign the routers
        $arrCaller = empty( $arrCaller ) ? $boot_router : $arrCaller;

        $__ctrl = $arrCaller['controller'] . "Controller";
        $__action = $arrCaller['action'] . "Action";
        $__event = new $__ctrl  ;
        $__event->params = $arrCaller;
        $__event->bootstrapping();
        $__event->_before_render();

        if(method_exists($__event,$__action)){
            if(
                !isset($__event->dispatch['preDispatchExclude']) 
                || !in_array($__action,$__event->dispatch['preDispatchExclude'])
            ){
                app::call($__event,"__preDispatch");
            }

            app::call($__event,$__action,$arrParams);

            if(!isset($__event->dispatch['postDispatchExclude']) 
                || !in_array($__action,$__event->dispatch['postDispatchExclude'])
            ){
                app::call($__event,"__postDispatch");
            }
        }
        else{
            if( self::__def()->sysConfig('DEBUG_MODE') > 0){
                try{
                    throw new AppException('Trace:');
                }
                catch (AppException $e){
                    pre(("<p style=\"font-family:Courier, monospace;font-weight:normal;font-size:12px;color:red\">AppException Trace:\nYou can do any one of following: \n1. Create the following method in " . CONTROLLER_PATH . " \n" . "\t class " . $__ctrl . " extends appRain_Base_Core \n\t {\n\t\t public $" . "name = '" . $arrCaller['controller'] . "';\n\t\t public function {$__action}()\n\t\t {\n\t\t }\n\t }\n2. Crate an alies of this URL form URI Manager</p>"));
                }
            }
            else{
                self::__transfer();
            }
        }

        # Manage Gloabl Redirection
        if( self::$_appDef->sysConfig('GLOBAL_REDIRECTION') ){
            $globalrouter = (!empty($definition['globalrouter'])) 
                ? $definition['globalrouter'] 
                : Array(
                    'controller' => 'home',
                    'action' => 'index'
                );
            if(
               ($globalrouter['controller'] != $arrCaller['controller'] 
                || $globalrouter['action'] != $arrCaller['action']) 
                && $__event->layout != 'admin'
              ){
                self::__transfer(DS . implode(DS,$globalrouter));
            }
        }

        $__event->render($arrCaller['controller'] . DS . $arrCaller['action']);
        $__event->_after_render();
    }
}
// END APP FACTORY